package dyyx;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class JvmPauseMonitor extends Thread {

    private static final long SLEEP_INTERVAL_MS = 500;

    // 时间差在此阈值内认为没有停顿
    // private final long thresholdMs = 10;

    // 时间分桶
    // private final long WIDTH = 10;
    private static final int MAX_INDEX = 1000;
    
    private static final int MAX_COUNT = 100;


    private static final long[] counts = new long[MAX_INDEX + 1];

    public static void main(String[] args) throws Exception {

    }

    private static int getIndex(long time) {
        if (time <= 0) {
            return 0;
        }

        int index = 0;
        if (time > MAX_INDEX) {
            index = MAX_INDEX;
        } else {
            index = (int) time;
        }
        return index;
    }

    @Override
    public void run() {

        while (true) {
            long start = System.currentTimeMillis();
            try {
                Thread.sleep(SLEEP_INTERVAL_MS);
                long end = System.currentTimeMillis();
                long time = end - start;

                long tmp = time - SLEEP_INTERVAL_MS;
                // if(tmp < thresholdMs) {
                // continue;
                // }
                int index = getIndex(tmp);
                counts[index] = counts[index] + 1;

            } catch (Throwable e) {
                // ignore
            }

        }
    }

    public synchronized static long[] getCounts() {
        long[] countsNew = new long[MAX_INDEX + 1];
        for (int i = 0; i <= MAX_INDEX; i++) {
            countsNew[i] = counts[i];
        }
        return countsNew;
    }

    public static String getCountInfo(int bucketWidth, int maxCount) {
        if (maxCount <= 0 || maxCount > MAX_COUNT) {
            maxCount = MAX_COUNT;
        }
        if (bucketWidth <= 0 ) {
            bucketWidth = 5;
        }
        StringBuilder sb = new StringBuilder();
        sb.append("bucketWidth=" + bucketWidth+"\n");
        sb.append("maxCount=" + maxCount+"\n");
        long[] arr = getCounts();
        long total = getTotalStopTime(arr);
        sb.append("total=" + total+"\n");

        // sb.append("\n");

        sb.append(getTopCounts(arr, bucketWidth, maxCount));

        return sb.toString();
    }

    private static long getTotalStopTime(long[] arr) {
        if (arr == null || arr.length <= 0) {
            return 0;
        }
        long total = 0;
        for (long item : arr) {
            total = total + item;
        }
        return total;
    }

    private static String getTopCounts(long[] arr, int bucketWidth, int maxCount) {

        // bucketWidth 5ms 10ms 20ms 50ms 100ms
        if (arr == null || arr.length <= 0) {
            return "";
        }
        int count = (arr.length / bucketWidth) + 1;
        List<CountInfo> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            CountInfo info = buildCountInfo(arr, bucketWidth, i);
            if (info == null) {
                continue;
            }
            list.add(info);
        }

        Collections.sort(list);
        int size = list.size();
        int end = size;
        if (maxCount < size) {
            end = maxCount;
        }

        StringBuilder sb = new StringBuilder();
        // sb.append("bucketWidth="+bucketWidth);
        // sb.append("maxCount="+maxCount);

        for (int i = 0; i < end; i++) {
            CountInfo info = list.get(i);
            sb.append(info.time + "=" + info.count+"\n");
        }

        return sb.toString();
    }

    private static CountInfo buildCountInfo(long[] arr, int bucketWidth, int countIndex) {
        int count = (arr.length / bucketWidth) + 1;
        if (countIndex >= count) {
            return null;
        }
        int start = countIndex * bucketWidth;
        int end = (countIndex + 1) * bucketWidth;
        long total = 0;
        for (int i = start; i < end; i++) {
            if (i >= arr.length) {
                continue;
            }
            total = total + arr[i];
        }
        if (total <= 0) {
            return null;
        }
        CountInfo info = new CountInfo();
        info.time = countIndex * bucketWidth;
        info.count = total;
        return info;
    }

}
